
/*************************************************************************
* Copyright (c) 2008, ShenZhen Coship Electronic Ltd Co.
* All rights reserved.
* 
* File Name:		DecBuf.cpp
* Summary:			implementation of the CircleBuf and DecBuf class.
* 
* Current Version:	1.0
* Author(s):
/------------------------------------------------------------------------/
revision			author				reason					date
1.0					Ding Ning			Initialize Version		2008-6-18
/------------------------------------------------------------------------/
*************************************************************************/

#include "StdAfx.h"
#include "DecBuf.h"

CircleBuf::CircleBuf()
{
	m_pBuf = NULL;
}

CircleBuf::~CircleBuf()
{
	Release();
}

bool CircleBuf::Create(int size)
{
	if (size <= 0)
		return false;

	if (m_pBuf != NULL)
		free(m_pBuf);

	m_pBuf = (char*)malloc(size);
	m_nSize = size;
	m_nStock = 0;
	m_nReadPos = 0;
	m_nWritePos = 0;
	m_evtNoFull.Set();

	return true;
}

void CircleBuf::Release()
{
	if (m_pBuf == NULL)
		return;

	free(m_pBuf);
	m_pBuf = NULL;
	m_nSize = 0;
	m_nStock = 0;
	m_nReadPos = 0;
	m_nWritePos = 0;
}

int CircleBuf::Read(void* buf, int size)
{
	HANDLE hnoempty = (HANDLE)m_evtNoEmpty;
	DWORD ret = ::MsgWaitForMultipleObjects(1, &hnoempty, FALSE, 1000, QS_ALLEVENTS);
	if (ret == WAIT_OBJECT_0 + 1)
	{
		MSG msg;
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
				return 0;
			TranslateMessage(&msg);
			DispatchMessage(&msg); 
		}
	}
	else if (ret == WAIT_FAILED)
		return -1;
	else if (ret == WAIT_TIMEOUT)
		return 0;

	AutoLock lock(&m_csAccess);

	if (m_nStock < size)
		return 0;

	int left = 0;
	int offs = m_nWritePos - m_nReadPos;
	if (offs > 0)
	{
		memcpy(buf, &m_pBuf[m_nReadPos], size);
		m_nReadPos += size;
	}
	else
	{
		offs = m_nSize - m_nReadPos;
		if (offs > size)
		{
			memcpy(buf, &m_pBuf[m_nReadPos], size);
			m_nReadPos += size;
		}
		else
		{
			memcpy(buf, &m_pBuf[m_nReadPos], offs);
			left = size - offs;
			memcpy(&((char*)buf)[offs], m_pBuf, left);
			m_nReadPos = left;
		}
	}

	m_nStock -= size;

	if (m_nStock != 0)
		m_evtNoEmpty.Set();

	m_evtNoFull.Set();

	return size;
}

int CircleBuf::Write(void* buf, int size)
{
	HANDLE hnofull = (HANDLE)m_evtNoFull;
	DWORD ret = MsgWaitForMultipleObjects(1, &hnofull, FALSE, 1000, QS_ALLEVENTS);
	if (ret == WAIT_OBJECT_0 + 1)
	{
		MSG msg;
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
				return 0;
			TranslateMessage(&msg);
			DispatchMessage(&msg); 
		}
	}
	else if (ret == WAIT_FAILED)
		return -1;
	else if (ret == WAIT_TIMEOUT)
		return 0;

	AutoLock lock(&m_csAccess);  

	if (m_nStock + size > m_nSize)
		return 0;

	int left = 0;
	int offs = m_nSize - m_nWritePos;
	if (offs > size)
	{
		memcpy(&m_pBuf[m_nWritePos], buf, size);
		m_nWritePos += size;
	}
	else
	{
		memcpy(&m_pBuf[m_nWritePos], buf, offs);
		left = size - offs;
		memcpy(m_pBuf, &((char*)buf)[offs], left);
		m_nWritePos = left;
	}

	m_nStock += size;
	
	if (m_nStock != m_nSize)
		m_evtNoFull.Set();

	m_evtNoEmpty.Set();

	return size;
}

int CircleBuf::GetStock()
{
	AutoLock lock(&m_csAccess);
	
	return m_nStock;
}

void CircleBuf::Reset()
{
	AutoLock lock(&m_csAccess);
	
	m_nReadPos = 0;
	m_nWritePos = 0;
	m_nStock = 0;
	m_evtNoEmpty.Reset();
	m_evtNoFull.Set();
}

//DecBuf;
DecBuf::DecBuf(CircleBuf* buf)
{
	m_pCirBuf = buf;
}

DecBuf::~DecBuf()
{

}

HRESULT DecBuf::CreateObj()
{
	m_bStop = false;
	return S_OK;
}

HRESULT DecBuf::Read(void* buf, size_t bufsize, size_t* readed)
{
	bool bout = false;
	HRESULT ret = S_OK;

	do
	{
		* readed = m_pCirBuf->Read(buf, bufsize);

		if (* readed > 0)
			bout = true;
		else if (* readed < 0)
		{
			bout = true;
			ret = E_FAIL;
		}
		else
		{
			if (m_bStop)
			{
				bout = true;
				ret = E_FAIL;
			}
		}
	}
	while (!bout);

	return ret;
}

HRESULT DecBuf::Rewind()
{
	return S_OK;
}

HRESULT	DecBuf::Release()
{
	return S_OK;
}

void DecBuf::Stop()
{
	m_bStop = true;
}